package com.yuxl.admin.manager.auth.server.controller;

import com.yuxl.admin.common.core.utils.R;
import com.yuxl.admin.manager.auth.core.entity.AuthRole;
import com.yuxl.admin.manager.auth.core.entity.AuthUser;
import com.yuxl.admin.manager.auth.core.repository.AuthRoleRepository;
import com.yuxl.admin.manager.auth.core.repository.AuthUserRepository;
import com.yuxl.admin.manager.auth.core.repository.AuthUserRoleRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;
@RequiredArgsConstructor
@RestController
@RequestMapping("/manager/user")
@Tag(name = "用户管理", description = "用户的 CRUD 操作")
public class AuthUserController {

    private final AuthUserRepository authUserRepository;
    private final AuthUserRoleRepository authUserRoleRepository;
    private final AuthRoleRepository authRoleRepository;
    private final PasswordEncoder passwordEncoder;

    /**
     * 创建新用户
     * @param user 要创建的用户对象
     * @return 创建成功的用户对象
     */
    @PostMapping
    @Operation(summary = "创建新用户", description = "创建一个新的用户")
    public Mono<R<AuthUser>> create(@RequestBody AuthUser user) {
        user.setCreateTime(LocalDateTime.now());
        // 设置创建时间
        user.setUpdateTime(LocalDateTime.now());
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        // 设置更新时间
        user.setCreateTime(LocalDateTime.now());
        return R.ok(authUserRepository.save(user));
        // 保存新用户到数据库
    }

    /**
     * 根据ID获取用户
     * @param id 用户ID
     * @return 用户对象
     */
    @GetMapping("/{id}")
    @Operation(summary = "获取用户", description = "根据ID获取用户信息")
    public Mono<R<AuthUser>> getUserById(@PathVariable Long id) {
        return R.ok(authUserRepository.findById(id));
    }

    /**
     * 更新用户信息
     * @param id 要更新的用户ID
     * @param user 包含更新信息的用户对象
     * @return 更新后的用户对象
     */
    @PutMapping("/{id}")
    @Operation(summary = "更新用户", description = "更新指定ID的用户信息")
    public Mono<R<AuthUser>> updateUser(@PathVariable Long id, @RequestBody AuthUser user) {
        return authUserRepository.findById(id)
                // 根据ID查找现有用户
                .flatMap(existingUser -> {
                    existingUser.setUsername(user.getUsername());
                    existingUser.setPassword(user.getPassword());
                    existingUser.setUpdateTime(LocalDateTime.now());
                    // 更新用户信息
                    return R.ok(authUserRepository.save(existingUser));
                    // 保存更新后的用户
                })
                .switchIfEmpty(R.failed("更新用户失败"));
    }

    /**
     * 删除用户
     * @param id 要删除的用户ID
     * @return 无返回值
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "删除用户", description = "删除指定ID的用户")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public Mono<R<Void>> deleteUser(@PathVariable Long id) {
        return R.ok(authUserRepository.deleteById(id));
        // 根据ID删除用户
    }

    /**
     * 获取所有用户
     * @return 所有用户的列表
     */
    @GetMapping
    @Operation(summary = "获取所有用户", description = "获取所有用户的列表")
    public Mono<R<List<AuthUser>>> getAllUsers() {
        return R.ok(authUserRepository.findAll());
        // 获取所有用户
    }

    /**
     * 搜索用户
     * @param username 用户名（可选）
     * @param startTime 开始时间（可选）
     * @param endTime 结束时间（可选）
     * @return 符合条件的用户列表
     */
    @GetMapping("/search")
    @Operation(summary = "搜索用户", description = "根据用户名和时间范围搜索用户")
    public Mono<R<List<AuthUser>>> searchUsers(
            @RequestParam(required = false) String username,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
        if (username != null && startTime != null && endTime != null) {
            return R.ok(authUserRepository.findByUsernameAndCreateTimeBetween(username, startTime, endTime));
        } else if (username != null) {
            return R.ok(authUserRepository.findByUsername(username).flux());
        } else if (startTime != null && endTime != null) {
            return R.ok(authUserRepository.findByCreateTimeBetween(startTime, endTime));
        } else {
            return R.ok(authUserRepository.findAll());
        }
    }

    /**
     * 分页获取用户
     * @param page 页码
     * @param size 每页大小
     * @param username 用户名（可选）
     * @param startTime 开始时间（可选）
     * @param endTime 结束时间（可选）
     * @return 分页后的用户列表
     */
    @GetMapping("/page")
    @Operation(summary = "分页获取用户", description = "分页获取用户列表，支持搜索条件")
    public Mono<R<List<AuthUser>>> getUsersPage(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String username,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
        Flux<AuthUser> userFlux;
        if (username != null && startTime != null && endTime != null) {
            userFlux = authUserRepository.findByUsernameAndCreateTimeBetween(username, startTime, endTime);
        } else if (username != null) {
            userFlux = authUserRepository.findByUsername(username).flux();
        } else if (startTime != null && endTime != null) {
            userFlux = authUserRepository.findByCreateTimeBetween(startTime, endTime);
        } else {
            userFlux = authUserRepository.findAll();
        }

        return R.ok(userFlux
                .sort((u1, u2) -> u2.getCreateTime().compareTo(u1.getCreateTime()))
                .skip((long) page * size)
                .take(size));
    }

    /**
     * 获取用户数量
     * @param username 用户名（可选）
     * @param startTime 开始时间（可选）
     * @param endTime 结束时间（可选）
     * @return 符合条件的用户数量
     */
    @GetMapping("/count")
    @Operation(summary = "获取用户数量", description = "获取符合条件的用户数量")
    public Mono<R<Long>> getUserCount(
            @RequestParam(required = false) String username,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
            @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
        if (username != null && startTime != null && endTime != null) {
            return R.ok(authUserRepository.findByUsernameAndCreateTimeBetween(username, startTime, endTime).count());
        } else if (username != null) {
            return R.ok(authUserRepository.findByUsername(username).map(user -> 1L).defaultIfEmpty(0L));
        } else if (startTime != null && endTime != null) {
            return R.ok(authUserRepository.findByCreateTimeBetween(startTime, endTime).count());
        } else {
            return R.ok(authUserRepository.count());
        }
    }

    /**
     * 获取用户的角色
     * @return 用户的角色列表
     */
    @GetMapping("/roles/{id}")
    @Operation(summary = "获取用户角色", description = "获取指定用户ID或用户名的所有角色")
    public Mono<R<List<AuthRole>>> getRolesByUser(
            @PathVariable Long id
    ) {
        if (id != null) {
            return R.ok(authUserRoleRepository.findByUserId(id)
                    .flatMap(userRole -> authRoleRepository.findById(userRole.getRoleId())));
        } else {
            return R.ok();
        }
    }

    @PostMapping("/createTestUser")
    @Operation(summary = "创建测试用户", description = "创建一个用于测试的用户")
    public Mono<R<AuthUser>> createTestUser() {
        AuthUser testUser = new AuthUser();
        testUser.setUsername("testuser");
        testUser.setPassword("password"); // 在实际应用中，应该对密码进行加密
        testUser.setCreateTime(LocalDateTime.now());
        testUser.setUpdateTime(LocalDateTime.now());
        return R.ok(authUserRepository.save(testUser));
    }
}
